package io.kimmking.rpcfx.demo.consumer;

import io.kimmking.rpcfx.api.Filter;
import io.kimmking.rpcfx.api.LoadBalancer;
import io.kimmking.rpcfx.api.Router;
import io.kimmking.rpcfx.api.RpcfxRequest;
import io.kimmking.rpcfx.context.RpcfxContext;
import io.kimmking.rpcfx.proxy.RpcfxCglib;
import io.kimmking.rpcfx.demo.api.User;
import io.kimmking.rpcfx.demo.api.UserService;
import io.kimmking.rpcfx.register.center.api.DiscoveryInfo;
import io.kimmking.rpcfx.register.center.api.ProviderInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@SpringBootApplication
public class RpcfxClientApplication {


    public static void main(String[] args) {
        RpcfxCglib rpcfxCglib = startWithRedis();
        CustomFilter customFilter = new CustomFilter();
        //rpc
        UserService userService = rpcfxCglib.create(UserService.class,
                DiscoveryInfo.builder().serviceName(UserService.class.getName()).build(),
                customFilter
        );
        //rcp调用，同时传递上下信息
        // 上下文在请求结束之后会自动删除,后续的其它请求也不会再有上下文信息
        RpcfxContext.put("client-ctx", "123");
        User user = userService.findById(1);
        System.out.println("rpc find user id=1 from server: " + user.getName());

        //mock
        UserService userMockService = rpcfxCglib.createMock(UserService.class, MockUserServiceImpl.class);
        user = userMockService.findById(1);
        System.out.println("mock find user id=1 from server: " + user.getName());

        //泛化调用
        DiscoveryInfo discoveryInfo = DiscoveryInfo.builder().serviceName(UserService.class.getName()).build();
        Object result = rpcfxCglib.genericCall(discoveryInfo, "findById", new Object[]{1}, customFilter);
        System.out.println("generic find user id=1 from server: " + result);
    }
    private static RpcfxCglib startWithRedis() {
        String redisHost = "127.0.0.1";
        int redisPort = 6379;
        String namespace = "rpcfx";
        LoadBalancer loadBalancer = new RandomLoadBalancer();
        Router router = new AllRouter();
        return new RpcfxCglib(redisHost,redisPort, namespace, loadBalancer, router);
    }
    private static RpcfxCglib startWithZk() {
        String zkServer = "127.0.0.1:2181";
        String namespace = "rpcfx";
        LoadBalancer loadBalancer = new RandomLoadBalancer();
        Router router = new AllRouter();
        return new RpcfxCglib(zkServer, namespace, loadBalancer, router);
    }

    private static class BaseRouter implements Router {
        String tag;

        public BaseRouter(String tag) {
            this.tag = tag;
        }

        @Override
        public List<ProviderInfo> route(List<ProviderInfo> services, DiscoveryInfo providerInfo) {
            services = services.stream().filter(p -> {
                if (providerInfo.getGroup() != null && !providerInfo.getGroup().equals(p.getGroup())) {
                    return false;
                }
                if (providerInfo.getTag() != null && !providerInfo.getTag().equals(p.getTag())) {
                    return false;
                }
                if (providerInfo.getVersion() != null && !providerInfo.getVersion().equals(p.getVersion())) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());

            return services.stream().filter(p -> tag.equals(p.getTag())).collect(Collectors.toList());
        }
    }

    private static class AllRouter implements Router {
        @Override
        public List<ProviderInfo> route(List<ProviderInfo> services, DiscoveryInfo providerInfo) {
            return services;
        }
    }

    private static class RandomLoadBalancer implements LoadBalancer {
        @Override
        public ProviderInfo select(List<ProviderInfo> urls) {
            if (urls == null || urls.size() == 0) {
                throw new RuntimeException("未找到提供者");
            }
            return urls.get(new Random().nextInt(urls.size()));
        }
    }

    @Slf4j
    private static class CustomFilter implements Filter {
        @Override
        public boolean filter(RpcfxRequest request) {
            log.info("filter {} -> {}", this.getClass().getName(), request.toString());
            return true;
        }
    }
}



